/** Basic Preferences Object.
 * This reads and writes to a simple preferences file. (label=string)
 *
 * There is a vague plan to be able to subclass Preferences to write to other
 * config systems (KDE, Gnome, etc.) as needed.
 */

#include "mcp.h"
#include "configfile.h"
#include "preferences.h"

//  Default Preferences implementation                                    >fold>

class dp_Data
    {
  public:
    string key;
    string value;
    bool is_default;

    dp_Data (const string &arg_key, const string &arg_value,
             bool arg_is_default=false)
      : key(arg_key),
        value(arg_value),
        is_default(arg_is_default)
        {}
    };

class DefPref : public Preferences
    {
  public:
    DefPref () { changed = false; }
//    ~DefPref () { data.clear(); }  // TODO ensure this is not needed
    bool changed;
    
    ConfigProcessor *processor(const char *label);

//    virtual void set_default(const string *key, const string *value);
    virtual void set(const string &key, const string &value,
                     bool set_default = false);
    virtual const char *get(const string &key);
    virtual void unset(const string &key);

    virtual bool is_set(const string &key);
    virtual bool is_default(const string &key);

    vector<dp_Data> data;
    };

// ---------------------------------------------------------------------- <fold<
//  -   file storage                                                      >fold>

class PrefProcessor : public ConfigProcessor
    {
  public:
    DefPref *prefs;

    PrefProcessor (const char *arg_label, DefPref *arg_prefs)
        { label = arg_label; prefs = arg_prefs; }

    void data_read (const char *key, char *value)
        {
        prefs->changed = true;
        string tmpkey(key);
        string tmpval(value);
        dp_Data tmpobj(tmpkey, tmpval, false);
        prefs->data.push_back(tmpobj);
        }

    void write_data();
    };

void PrefProcessor::write_data ()
    {
    cfgfile->indent = 4;
    for ( unsigned int i = 0; i < prefs->data.size() ; i++ )
        if ( !prefs->data[i].is_default )
            cfgfile->write(prefs->data.at(i).key.c_str(), 16, true,
                           prefs->data.at(i).value.c_str());
    mcp->log_verbose(5, "DefPref: %d lines written\n", cfgfile->line_number);
    }

ConfigProcessor * DefPref::processor (const char *label)
    {
    return new PrefProcessor(label, this);
    }

// ---------------------------------------------------------------------- <fold<
//  -   setting values                                                  >fold>//

void DefPref::set (const string &key, const string &value, bool set_default)
    {
    for ( unsigned int i = 0; i < data.size(); i++ )
        if ( data.at(i).key.compare(key) == 0 )
            {
            // The preference was set already, ignore this default value
            if ( set_default && !data.at(i).is_default )
                return;

            data.at(i).is_default = set_default;
            data.at(i).value.assign(value);
            if ( !set_default )
                changed = true;
            return;
            }

    dp_Data newObj(key, value, set_default);
    data.push_back(newObj);
//    data.push_back(new dp_Data(key, value, set_default));
    if ( !set_default )
        changed = true;
    }

void DefPref::unset (const string &key)
    {
    for ( vector<dp_Data>::iterator it = data.begin(); it != data.end(); it++ ) 
        if ( it->key.compare(key) == 0 )
            {
            data.erase(it);
            return;
            }
    }

// -------------------------------------------------------------------- <fold<//
//  -   retrieving values                                                 >fold>

bool DefPref::is_set (const string &key)
    {
    for ( unsigned int i = 0; i < data.size(); i++ )
        if ( data.at(i).key.compare(key) == 0 )
            return true;
    return false;
    }

bool DefPref::is_default (const string &key)
    {
    for ( unsigned int i = 0; i < data.size(); i++ )
        if ( data.at(i).key.compare(key) == 0 )
            return data.at(i).is_default;
    return false;
    }

const char *DefPref::get (const string &key)
    {
    for ( unsigned int i = 0; i < data.size(); i++ )
        if ( data.at(i).key.compare(key) == 0 )
            return data.at(i).value.c_str();
    return 0;
    }

// ---------------------------------------------------------------------- <fold<

Preferences * Preferences::default_type ()
    { return (Preferences *)new DefPref(); }
